import { Controller, Headers, Get, Post, Param, Body, UsePipes, ValidationPipe, UploadedFile, UseInterceptors, Query, Put, Delete } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiQuery } from '@nestjs/swagger';
import { Injectable, Inject, forwardRef, BadRequestException, InternalServerErrorException } from '@nestjs/common';
import { TransformInterceptor } from 'src/interceptor/transform.interceptor';
import { FileInterceptor } from '@nestjs/platform-express';
import { MinioClient } from '../app.minio';
import { TransDto } from './task.dto';
import * as uuid from 'uuid';
const Fs = require('fs')
const ffmpeg = require('../utils/ffmpeg');
const path = require('path')
const task = new Map()

@ApiTags('任务')
@Controller('task')
@UseInterceptors(TransformInterceptor)
export class TaskController {

    @Post('trans')
    @ApiOperation({ summary: '开启一个转码' })
    async trans(@Body() body: TransDto) {
        console.log(body)
        return await new Promise(async resolve => {
            try {
                const taskId = uuid.v4()
                let content = new Buffer(0);
                const readerStream = await new MinioClient().getObject(body.bucketName, body.objectName);
                readerStream.on('data', chunk => {
                    content = Buffer.concat([content, chunk]);
                });
                readerStream.on('error', function (err) {
                    console.log(err.stack);
                    throw new BadRequestException(err.stack);
                })
                readerStream.on('end', () => {
                    mkdirSync(path.join(__dirname, `../../public/cache/${taskId}/`))
                    mkdirSync(path.join(__dirname, `../../public/${taskId}/`))
                    Fs.writeFileSync(path.join(__dirname, `../../public/cache/${taskId}/${taskId}.mp4`), content);
                    task.set(taskId, {
                        state: 2,
                        msg: '任务启动',
                        progress: 0,
                        key: null
                    })
                    this.transing(taskId, body)
                    resolve({
                        taskId
                    })
                });
            } catch (error) {
                throw new BadRequestException(error);
            }
        })
    }
    @Get(':id')
    @ApiOperation({ summary: '查询某个任务的状态' })
    async findTask(@Param('id') id) {
        if (!task.has(id)) {
            throw new BadRequestException("taskId出错");
        } else {
            if (task.get(id).state == 1) {
                let obj = {
                    state: task.get(id).state,
                    key: task.get(id).key,
                }
                setTimeout(() => {
                    task.delete(id)
                }, 1000);
                return obj
            } else {
                return {
                    state: task.get(id).state,
                    msg: task.get(id).msg,
                    progress: task.get(id).progress,
                    key: task.get(id).key,
                }
            }
        }
    }
    transing(taskId, body) {
        const [key, objectName] = fileName(body.objectName)
        task.get(taskId).msg = "转码中"
        task.get(taskId).state = 3
        if (body.type == 'hls') {
            const command = new ffmpeg(path.join(__dirname, `../../public/cache/${taskId}/${taskId}.mp4`))
            command.videoCodec('libx264') // 设置视频编解码器
                // .audioCodec('libfaac') // 设置 音频解码器
                .format('hls') // 输出视频格式
                .outputOptions('-hls_list_size 0') //  -hls_list_size n:设置播放列表保存的最多条目，设置为0会保存有所片信息，默认值为5
                .outputOption('-hls_time 10') // -hls_time n: 设置每片的长度，默认值为2。单位为秒
                .output(path.join(__dirname, `../../public/${taskId}/${objectName}.m3u8`)) // 输出文件
                .on('progress', (progress) => { // 监听切片进度
                    if(progress.percent){
                        task.get(taskId).progress = progress.percent
                    }else{
                        if( task.get(taskId).progress<=90){
                            task.get(taskId).progress+=5
                        }
                    }
                })
                .on('end', () => {
                    Fs.readdir(path.join(__dirname, `../../public/${taskId}/`), async (err, data) => {
                        if (err) throw new BadRequestException(err);
                        let a = []
                        for (let item of data) {
                            a.push(new MinioClient().putObject2(path.join(__dirname, `../../public/${taskId}/`) + item, { bucketName: body.bucketName, objectName: key + item }))
                        }
                        await Promise.all(a)
                        await removePromise(path.join(__dirname, `../../public/cache/${taskId}/`))
                        await removePromise(path.join(__dirname, `../../public/${taskId}/`))
                        task.get(taskId).state = 1
                        task.get(taskId).msg = '转码完成'
                        task.get(taskId).progress = 100
                        task.get(taskId).key = body.objectName + '.m3u8'
                    })
                })
                .run();
        }
    }

}

function mkdirSync(path) {
    if (!Fs.existsSync(path)) {
        Fs.mkdirSync(path)
    }
}
//解析文件目录和文件名
function fileName(file) {
    let a = file.split('/'), key = ''
    key = a.pop()
    return [a.join('/') + '/', key]
}
//删除文件夹
function removePromise(dir) {
    return new Promise(function (resolve, reject) {
        //先读文件夹
        Fs.stat(dir, function (err, stat) {
            if (stat.isDirectory()) {
                Fs.readdir(dir, function (err, files) {
                    files = files.map(file => path.join(dir, file)); // a/b  a/m
                    files = files.map(file => removePromise(file)); //这时候变成了promise
                    Promise.all(files).then(function () {
                        Fs.rmdir(dir, resolve);
                    })
                })
            } else {
                Fs.unlink(dir, resolve)
            }
        })

    })
}